#include "common.h"
#include "gl_util.h"

#include <android/bitmap.h>

auto gVertexShader =
        "attribute vec4 aPosition;\n"
        "attribute vec2 a_TexCoord;\n"
        "varying vec2 v_TexCoord;\n"
        "void main() {\n"
        "  gl_Position = aPosition;\n"
        "  v_TexCoord = a_TexCoord;\n"
        "}\n";

auto gFragmentShader =
        "precision mediump float;\n"
        "uniform sampler2D samplerY;\n"
        "uniform sampler2D samplerU;\n"
        "uniform sampler2D samplerV;\n"
        "varying vec2 v_TexCoord;\n"
        "void main() {\n"
        "   vec3 yuv;\n"
        "   vec3 rgb;\n"
        "   yuv.x = texture2D(samplerY, v_TexCoord).r;\n"
        "   yuv.y = texture2D(samplerU, v_TexCoord).r - 0.5;\n"
        "   yuv.z = texture2D(samplerV, v_TexCoord).r - 0.5;\n"
        "   rgb = mat3(1, 1, 1, 0, -0.39465,  2.03211, 1.13983, -0.58060, 0) * yuv;\n"
        "   gl_FragColor = vec4(rgb, 1);\n"
        "}\n";

//auto gFragmentShader =
//        "precision mediump float;\n"
//        "uniform sampler2D samplerY;\n"
//        "uniform sampler2D samplerU;\n"
//        "uniform sampler2D samplerV;\n"
//        "varying vec2 v_TexCoord;\n"
//        "void main() {\n"
//        "   vec3 yuv;\n"
//        "   vec3 rgb;\n"
//        "   yuv.x = texture2D(samplerY, v_TexCoord).r;\n"
//        "   yuv.y = texture2D(samplerU, v_TexCoord).r - 0.5;\n"
//        "   yuv.z = texture2D(samplerV, v_TexCoord).r - 0.5;\n"
//        "   rgb.r = yuv.x + 1.13983 * yuv.z;\n"
//        "   rgb.g = yuv.x - 0.39465*yuv.y - 0.58060*yuv.z;\n"
//        "   rgb.b = yuv.x + 2.03211*yuv.y;\n"
//        "   gl_FragColor = vec4(rgb, 1);\n"
//        "}\n";



const GLfloat gTriangleVertices[] = {
        -0.5f, 0.5f,  0.0f, 1 - 1.0f,
        -0.5f, -0.5f, 0.0f, 1 - 0.0f,
        0.5f,  0.5f,  1.0f, 1 - 1.0f,
        0.5f,  -0.5f, 1.0f, 1 - 0.0f};


GLuint gProgram;
GLuint gaPositionHandle;
GLuint gaTexCoordHandle;
GLuint uTextureSamplerYHandle;
GLuint uTextureSamplerUHandle;
GLuint uTextureSamplerVHandle;

extern "C" JNIEXPORT void JNICALL
Java_com_example_king_openglenvdemo_nativegl_GLES2JNILib_init(
        JNIEnv* env,
        jobject obj,
        jint width,
        jint height) {

    glViewport(0, 0, width, height);

    gProgram = linkProgram(gVertexShader, gFragmentShader);
    if (!gProgram) {
        LOGE("Could not create program.");
        return;
    }

    glUseProgram(gProgram);

    gaPositionHandle = glGetAttribLocation(gProgram, "aPosition");
    glVertexAttribPointer(gaPositionHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), gTriangleVertices);
    glEnableVertexAttribArray(gaPositionHandle);

    gaTexCoordHandle = glGetAttribLocation(gProgram, "a_TexCoord");
    glVertexAttribPointer(gaTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), gTriangleVertices + 2);
    glEnableVertexAttribArray(gaTexCoordHandle);


    uTextureSamplerYHandle = glGetUniformLocation(gProgram, "samplerY");
    uTextureSamplerUHandle = glGetUniformLocation(gProgram, "samplerU");
    uTextureSamplerVHandle = glGetUniformLocation(gProgram, "samplerV");

    LOGD("-----------------------------------init");
}

extern "C" JNIEXPORT void JNICALL
Java_com_example_king_openglenvdemo_nativegl_GLES2JNILib_step(
        JNIEnv* env,
        jobject obj,
        jstring yuvpath) {

    const char * file_path = env->GetStringUTFChars(yuvpath, 0);
    if (!file_path) {
        LOGE("file path empty!");
        return;
    }

    int yuv_width = 240;
    int yuv_height = 320;

    GLuint textureYID;
    GLuint textureUID;
    GLuint textureVID;

    FILE* fp = fopen(file_path, "rb");
    int file_len = yuv_width * yuv_height * 1.5f;
    char * yuvDataBuf = static_cast<char *>(malloc(file_len));

    if (fp) {
        fread(yuvDataBuf, 1, file_len, fp);
        fclose(fp);
    }

    glGenTextures(1, &textureYID);
    glGenTextures(1, &textureUID);
    glGenTextures(1, &textureVID);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureYID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width, yuv_height,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerYHandle, 0);


    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureUID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width/2, yuv_height/2,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf + yuv_width * yuv_height);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerUHandle, 1);


    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, textureVID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width/2, yuv_height/2,
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yuvDataBuf + yuv_width * yuv_height * 5 / 4);
    glGenerateMipmap(GL_TEXTURE_2D);
    glUniform1i(uTextureSamplerVHandle, 2);


    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    free(yuvDataBuf);
    env->ReleaseStringUTFChars(yuvpath, file_path);
}